package net.yambal.RTM.RestWrapper
{
	import flash.events.EventDispatcher;
	
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.InvokeEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.http.HTTPService;
	
	import net.yambal.RTM.Event.RestErrorEvent;
	import net.yambal.RTM.Event.RestEvent;
	
	[Event(name="rtm_result", type="net.yambal.RTM.Event.RestEvent")]
	[Event(name="rtm_fault", type="net.yambal.RTM.Event.RestErrorEvent")] 
	[Event(name="fault", type="mx.rpc.events.FaultEvent")]
	[Event(name="invoke", type="flash.events.InvokeEvent")] 
	public class RestService extends EventDispatcher
	{
		
		public var service_url:String = "http://www.rememberthemilk.com/services/rest/";
		public var method:String;
		public var api_key:String;
		public var shared_secret:String;
		public var frob:String;
		public var token:String;
		
		private var _relay_obj:Object;

		private var _parameta:RestParameters;
		
		// Auth
		public static const METHOD_AUTH_GET_FROB:String = "rtm.auth.getFrob";
		public static const METHOD_AUTH_GET_TOKEN:String = "rtm.auth.getToken";
		public static const METHOD_AUTH_CHECK_TOKEN:String = "rtm.auth.checkToken";
		
		// Lists
		public static const METHOD_LISTS_GET_LISTS:String = "rtm.lists.getList";
		public static const METHOD_LISTS_ADD:String = "rtm.lists.add";
		public static const METHOD_LISTS_ARCHIVE:String = "rtm.lists.archive";
		public static const METHOD_LISTS_DELETE:String = "rtm.lists.delete";
		public static const METHOD_LISTS_SET_DEFAULT_LIST:String = "rtm.lists.setDefaultList";
		public static const METHOD_LISTS_SET_NAME:String = "rtm.lists.setName";
		public static const METHOD_LISTS_UN_ARCHIVE:String = "rtm.lists.unarchive";
		
		// Tasks
		public static const METHOD_TASKS_GET_LIST:String = "rtm.tasks.getList";
		public static const METHOD_TASKS_ADD:String = "rtm.tasks.add";
		public static const METHOD_TASKS_SET_NAME:String = "rtm.tasks.setName";
		public static const METHOD_TASKS_ADDTAGS:String = "rtm.tasks.addTags";
		public static const METHOD_TASKS_SET_TAGS:String = "rtm.tasks.setTags";
		public static const METHOD_TASKS_REMOVE_TAGS:String = "rtm.tasks.removeTags";
		public static const METHOD_TASKS_COMPLETE:String = "rtm.tasks.complete";
		public static const METHOD_TASKS_UNCOMPLETE:String = "rtm.tasks.uncomplete";
		public static const METHOD_TASKS_SET_PRIORITY:String = "rtm.tasks.setPriority";
		public static const METHOD_TASKS_MOVE_PRIORITY:String = "rtm.tasks.movePriority";
		public static const METHOD_TASKS_NOVE_TO:String = "rtm.tasks.moveTo";
		public static const METHOD_TASKS_POSTPONE:String = "rtm.tasks.postpone";
		public static const METHOD_TASKS_DELETE_TASK:String = "rtm.tasks.delete";
		public static const METHOD_TASKS_SET_ESTIMATE:String = "rtm.tasks.setEstimate";
		public static const METHOD_TASKS_SET_RECURRENCE:String = "rtm.tasks.setRecurrence";
		public static const METHOD_TASKS_SET_URL:String = "rtm.tasks.setURL";
		public static const METHOD_TASKS_SET_LOCATION:String = "rtm.tasks.setLocation";
		public static const METHOD_TASKS_SET_DUE_DATE:String = "rtm.tasks.setDueDate";
		
		// Tasks.notes
		public static const METHOD_NOTES_ADD:String = "rtm.tasks.notes.add";
		public static const METHOD_NOTES_EDIT:String = "rtm.tasks.notes.edit";
		public static const METHOD_NOTES_DELETE:String = "rtm.tasks.notes.delete";
		
		public static const METHOD_TIMELINES_CREATE:String = "rtm.timelines.create";
		
		
		public static const METHOD_TIMEZONE_GET_LIST:String = "rtm.timezones.getList";
		
		// Time
		public static const METHOD_TIME_CONVERT:String = "rtm.time.convert";
		public static const METHOD_TIME_PARSE:String = "rtm.time.parse";
		
		// Groups
		public static const METHOD_GROUPS_GET_LIST:String = "rtm.groups.getList";
		public static const METHOD_GROUPS_ADD:String = "rtm.groups.add";
		public static const METHOD_GROUPS_DELETE:String = "rtm.groups.delete";
		public static const METHOD_GROUPS_ADD_CONTACT:String = "rtm.groups.addContact";
		public static const METHOD_GROUPS_REMOVE_CONTACT:String = "rtm.groups.removeContact";
		
		// Contacts
		public static const METHOD_CONTACTS_GET_LIST:String = "rtm.contacts.getList";
		public static const METHOD_CONTACTS_ADD:String = "rtm.contacts.add";
		public static const METHOD_CONTACTS_DELETE:String = "rtm.contacts.delete";
		
		public static const METHOD_LOCATIONS_GET_LIST:String = "rtm.locations.getList";
		
		public static const METHOD_TRANSACTIONS_UNDO:String = "rtm.transactions.undo";
		
		
		public function RestService(method:String = null, shared_secret:String = null, relay_obj:Object=null)
		{
			this.method = method;
			this.shared_secret = shared_secret;
			this._relay_obj = relay_obj;
			
			this._parameta = new RestParameters();
			this._parameta.addParam("method", method);
		}
		
		public function addParameta(name:String, value:String):void{
			this._parameta.addParam(name, value);
			if(name == "api_key"){
				this.api_key = value;
			}
			if(name == "frob"){
				this.frob = value;
			}
			if(name == "auth_token" || name == "token"){
				this.token = value;
			}
		}

		public function send(is_status_check:Boolean = false, timeout_sec:Number = 10.0):void{
			trace("send:" + this.method);
			var hs:HTTPService = new HTTPService();
			hs.method = "GET";
			hs.resultFormat = "xml";
			hs.requestTimeout = timeout_sec;
			
			trace("\tshared_secret:" + this.shared_secret);
			trace("\t" + this._parameta.getParameterString());
			
			if(this.shared_secret){
				trace("\t\tsecret　mode");
				hs.request = this._parameta.getParameterObjectWithSig(this.shared_secret);

			}else{
				hs.request = this._parameta.getParameterObject();
			}
			
			hs.url = this.service_url;
			hs.addEventListener(InvokeEvent.INVOKE, this.onInvoke);
			hs.addEventListener(ResultEvent.RESULT, this.onResult);
			hs.addEventListener(FaultEvent.FAULT, this.onFault);
			hs.send();
		}
		
		// HTTPServiceにてonInvoke
		private function onInvoke(e:InvokeEvent):void{
			trace("onInvoke");
			var hs:HTTPService = e.currentTarget as HTTPService;
			hs.removeEventListener(InvokeEvent.INVOKE, this.onInvoke);
			//hs.removeEventListener(ResultEvent.RESULT, this.onResult);
			//hs.removeEventListener(FaultEvent.FAULT, this.onFault);
			
			this.dispatchEvent(new InvokeEvent(InvokeEvent.INVOKE, false, false));
		}
		
		// HTTPServiceにてfault
		private function onFault(e:FaultEvent):void{
			var hs:HTTPService = e.currentTarget as HTTPService;
			hs.removeEventListener(ResultEvent.RESULT, this.onResult);
			hs.removeEventListener(FaultEvent.FAULT, this.onFault);
			
			trace(e.message.body.faultCode);
			//faultString
			this.dispatchEvent(new FaultEvent(FaultEvent.FAULT, false, false, e.fault, e.token, e.message));
		}
		
		// HTTPServiceにてレスポンス
		private function onResult(e:ResultEvent):void{
			trace("onResult");
			
			var hs:HTTPService = e.currentTarget as HTTPService;
			hs.removeEventListener(ResultEvent.RESULT, this.onResult);
			hs.removeEventListener(FaultEvent.FAULT, this.onFault);
			
			var x:XML = new XML(e.result);
			if(x.@stat != "ok"){
				this.dispatchEvent(new RestErrorEvent(RestErrorEvent.RTM_FAULT, x.err.@code, x.err.@msg, this._relay_obj));
			}else{
				this.dispatchEvent(new RestEvent(RestEvent.RTM_RESULT, x, this._relay_obj));
			}
		}
		
		public function get relay_obj():Object{
			return this._relay_obj;
		}
	}
}